package com.stox.shared.model;

public class LineBreak extends Bar {

	private final boolean up;
	private final int reversalAmount;
	private final LineBreak previousLineBreak;

	public LineBreak(final boolean up, final int reversalAmount, final Bar bar, final LineBreak previousLineBreak) {
		this.up = up;
		this.reversalAmount = reversalAmount;
		this.previousLineBreak = previousLineBreak;
		if (null == previousLineBreak) {
			super.setHigh(bar.getHigh());
			super.setLow(bar.getLow());
		} else {
			super.setHigh(up ? bar.getHigh() : previousLineBreak.getLow());
			super.setLow(up ? previousLineBreak.getHigh() : bar.getLow());
		}
		setDate(bar.getDate());
		setOpen(bar.getOpen());
		setScrip(bar.getScrip());
		setScripId(bar.getScripId());
	}

	private void doConsume(final Bar bar) {
		setClose(bar.getClose());
		setDate(bar.getDate());
		setVolume(getVolume() + bar.getVolume());
	}

	private double getReversalPrice() {
		LineBreak lineBreak = this;
		double value = up ? Double.MAX_VALUE : Double.MIN_VALUE;
		for (int index = 0; index < reversalAmount; index++) {
			value = up ? Math.min(value, lineBreak.getLow()) : Math.max(value, lineBreak.getHigh());
			if (null == lineBreak.previousLineBreak) {
				break;
			} else {
				lineBreak = lineBreak.previousLineBreak;
			}
		}
		return value;
	}

	public LineBreak consume(final Bar bar) {
		final double value = bar.getClose();
		final double reversalPrice = getReversalPrice();
		if (up) {
			if (value > getHigh()) {
				return new LineBreak(up, reversalAmount, bar, this);
			} else {
				if (value < reversalPrice) {
					return new LineBreak(!up, reversalAmount, bar, this);
				} else {
					doConsume(bar);
					return this;
				}
			}
		} else {
			if (value < getLow()) {
				return new LineBreak(up, reversalAmount, bar, this);
			} else {
				if (value > reversalPrice) {
					return new LineBreak(!up, reversalAmount, bar, this);
				} else {
					doConsume(bar);
					return this;
				}
			}
		}
	}

	public boolean isUp() {
		return up;
	}

	@Override
	public void setHigh(final double high) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void setLow(final double low) {
		throw new UnsupportedOperationException();
	}

}
